package com.shrcl.engineerprocess.domain.impl;

import com.google.common.base.Objects;
import com.google.common.collect.Iterables;
import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerProcessSequenceService;
import com.shrcl.engineerprocess.domain.EngineerProject;
import com.shrcl.engineerprocess.domain.EngineerProjectAssignment;
import com.shrcl.engineerprocess.domain.EngineerProjectJob;
import com.shrcl.engineerprocess.domain.EngineerProjectJobStatus;
import com.shrcl.engineerprocess.domain.EngineerWorkOrder;
import com.shrcl.engineerprocess.domain.impl.EngineerProjectImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerWorkOrderImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerProjectJobProxy;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERPROJECTJOB_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineerprojectjob")
public class EngineerProjectJobImpl extends BaseModelObject implements EngineerProjectJob {
  public EngineerProjectJobImpl() {
    super();
  }
  
  public EngineerProjectJobImpl(final EngineerProject engineerProject) {
    super();
    this.engineerProject = engineerProject;
  }
  
  private EngineerProjectJobStatus Status;
  
  public EngineerProjectJobStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    this.checkValid();
    Status=EngineerProjectJobStatus.created;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectJobEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _execute() {
    
    Status=EngineerProjectJobStatus.executing;
  }
  
  public void execute() {
    if(Status==EngineerProjectJobStatus.created){
    	_execute();
    	getModelObjectLogService().createLog(this,"Status","execute");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectJobEventsManager.class).fireExecute(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private EngineerWorkOrder _createWorkOrder(final Procedure1<? super EngineerWorkOrder> init) {
    EngineerWorkOrder _createAndAddtoEngineerWorkOrders = this.createAndAddtoEngineerWorkOrders();
    final Procedure1<EngineerWorkOrder> _function = new Procedure1<EngineerWorkOrder>() {
        public void apply(final EngineerWorkOrder it) {
          init.apply(it);
          BeanFactory _beanFactory = EngineerProjectJobImpl.this.getBeanFactory();
          EngineerProcessSequenceService _bean = _beanFactory.<EngineerProcessSequenceService>getBean(EngineerProcessSequenceService.class);
          String _nextWorkOrderSequence = _bean.getNextWorkOrderSequence();
          it.setSid(_nextWorkOrderSequence);
        }
      };
    EngineerWorkOrder _doubleArrow = ObjectExtensions.<EngineerWorkOrder>operator_doubleArrow(_createAndAddtoEngineerWorkOrders, _function);
    return _doubleArrow;
  }
  
  public EngineerWorkOrder createWorkOrder(final Procedure1<? super EngineerWorkOrder> init) {
    if(Status==EngineerProjectJobStatus.executing){
    	EngineerWorkOrder result = _createWorkOrder(init);
    	getModelObjectLogService().createLog(this,"Status","createWorkOrder");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectJobEventsManager.class).fireCreateWorkOrder(this,init);
    	return result;						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("Status.name()");
    }
  }
  
  private void _delWorkOrder(final EngineerWorkOrder engineerWorkOrder) {
    
    this.removeFromEngineerWorkOrders(engineerWorkOrder);
  }
  
  public void delWorkOrder(final EngineerWorkOrder engineerWorkOrder) {
    if(Status==EngineerProjectJobStatus.executing){
    	_delWorkOrder(engineerWorkOrder);
    	getModelObjectLogService().createLog(this,"Status","delWorkOrder");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectJobEventsManager.class).fireDelWorkOrder(this,engineerWorkOrder);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _$workOrderFinish() {
    
    boolean _isAllTaskFinishedorCancelled = this.isAllTaskFinishedorCancelled();
    if (_isAllTaskFinishedorCancelled) {
      Status=EngineerProjectJobStatus.finished;
    }
  }
  
  public void $workOrderFinish() {
    if(Status==EngineerProjectJobStatus.executing){
    	_$workOrderFinish();
    	getModelObjectLogService().createLog(this,"Status","$workOrderFinish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectJobEventsManager.class).fire$workOrderFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  private void _finish() {
    
    Status=EngineerProjectJobStatus.finished;
  }
  
  public void finish() {
    if(Status==EngineerProjectJobStatus.executing){
    	_finish();
    	getModelObjectLogService().createLog(this,"Status","finish");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerProjectJobEventsManager.class).fireFinish(this);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerProjectJobStatus.created==Status;
  }
  
  public Boolean isExecuting() {
    return com.shrcl.engineerprocess.domain.EngineerProjectJobStatus.executing==Status;
  }
  
  public Boolean isFinished() {
    return com.shrcl.engineerprocess.domain.EngineerProjectJobStatus.finished==Status;
  }
  
  public Boolean isCancelled() {
    return com.shrcl.engineerprocess.domain.EngineerProjectJobStatus.cancelled==Status;
  }
  
  private String jobName;
  
  public String getJobName() {
    return this.jobName;
  }
  
  public EngineerProjectJob setJobName(final String jobName) {
    this.jobName = jobName;
    return this;			
    
  }
  
  private Date date;
  
  public Date getDate() {
    return this.date;
  }
  
  public EngineerProjectJob setDate(final Date date) {
    this.date = date;
    return this;			
    
  }
  
  private String sid;
  
  public String getSid() {
    return this.sid;
  }
  
  public EngineerProjectJob setSid(final String sid) {
    this.sid = sid;
    return this;			
    
  }
  
  @JoinColumn(name = "engineerProject_id")
  @ManyToOne(targetEntity = EngineerProjectImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private EngineerProject engineerProject;
  
  public EngineerProject getEngineerProject() {
    return this.engineerProject;
  }
  
  public EngineerProjectJob setEngineerProject(final EngineerProject engineerProject) {
    this.engineerProject = engineerProject;
    return this;			
    
  }
  
  @OneToMany(targetEntity = EngineerWorkOrderImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "projectJob")
  private Collection<EngineerWorkOrder> engineerWorkOrders = new java.util.ArrayList<com.shrcl.engineerprocess.domain.EngineerWorkOrder>();;
  
  public Collection<EngineerWorkOrder> getEngineerWorkOrders() {
    return this.engineerWorkOrders;
  }
  
  public EngineerWorkOrder createAndAddtoEngineerWorkOrders() {
    getEngineerWorkOrders().size();
    com.shrcl.engineerprocess.domain.EngineerWorkOrder engineerWorkOrder = new com.shrcl.engineerprocess.domain.impl.EngineerWorkOrderImpl(this);
    getObjectFactory().create(engineerWorkOrder);
    getEngineerWorkOrders().add(engineerWorkOrder);
    engineerWorkOrder.start();
    return engineerWorkOrder;
    
  }
  
  public EngineerWorkOrder createAndAddtoEngineerWorkOrders(final Procedure1<EngineerWorkOrder> updater) {
    getEngineerWorkOrders().size();
    com.shrcl.engineerprocess.domain.EngineerWorkOrder engineerWorkOrder = new com.shrcl.engineerprocess.domain.impl.EngineerWorkOrderImpl(this);
    getObjectFactory().create(engineerWorkOrder);
    getEngineerWorkOrders().add(engineerWorkOrder);
    updater.apply(engineerWorkOrder);
    engineerWorkOrder.start();
    return engineerWorkOrder;
    
  }
  
  public EngineerProjectJob removeAllEngineerWorkOrders() {
    for(EngineerWorkOrder obj : this.engineerWorkOrders){
    	getObjectFactory().delete(obj);
    }
    this.engineerWorkOrders.clear();
    return this;	
    
  }
  
  public EngineerProjectJob removeFromEngineerWorkOrders(final EngineerWorkOrder engineerWorkOrder) {
    this.engineerWorkOrders.remove(engineerWorkOrder);
    getObjectFactory().delete(engineerWorkOrder);
    return this;
    
  }
  
  public Collection<EngineerProjectAssignment> getAllProjectAssignmentAssignments() {
    final Function1<EngineerWorkOrder,Collection<EngineerProjectAssignment>> _function = new Function1<EngineerWorkOrder,Collection<EngineerProjectAssignment>>() {
        public Collection<EngineerProjectAssignment> apply(final EngineerWorkOrder it) {
          Collection<EngineerProjectAssignment> _projectAssignments = it.getProjectAssignments();
          return _projectAssignments;
        }
      };
    Iterable<Collection<EngineerProjectAssignment>> _map = IterableExtensions.<EngineerWorkOrder, Collection<EngineerProjectAssignment>>map(this.engineerWorkOrders, _function);
    Iterable<EngineerProjectAssignment> _flatten = Iterables.<EngineerProjectAssignment>concat(_map);
    List<EngineerProjectAssignment> _list = IterableExtensions.<EngineerProjectAssignment>toList(_flatten);
    return _list;
  }
  
  public EngineerWorkOrder findWorkOrder(final Engineer eng) {
    EngineerWorkOrder _xblockexpression = null;
    {
      final Function1<EngineerWorkOrder,Boolean> _function = new Function1<EngineerWorkOrder,Boolean>() {
          public Boolean apply(final EngineerWorkOrder it) {
            Engineer _engineer = it.getEngineer();
            boolean _equals = Objects.equal(_engineer, eng);
            return Boolean.valueOf(_equals);
          }
        };
      Iterable<EngineerWorkOrder> _filter = IterableExtensions.<EngineerWorkOrder>filter(this.engineerWorkOrders, _function);
      List<EngineerWorkOrder> _list = IterableExtensions.<EngineerWorkOrder>toList(_filter);
      EngineerWorkOrder wo = IterableExtensions.<EngineerWorkOrder>head(_list);
      boolean _equals = Objects.equal(wo, null);
      if (_equals) {
        EngineerWorkOrder _createAndAddtoEngineerWorkOrders = this.createAndAddtoEngineerWorkOrders();
        final Procedure1<EngineerWorkOrder> _function_1 = new Procedure1<EngineerWorkOrder>() {
            public void apply(final EngineerWorkOrder it) {
              it.setEngineer(eng);
              BeanFactory _beanFactory = EngineerProjectJobImpl.this.getBeanFactory();
              EngineerProcessSequenceService _bean = _beanFactory.<EngineerProcessSequenceService>getBean(EngineerProcessSequenceService.class);
              String _nextWorkOrderSequence = _bean.getNextWorkOrderSequence();
              it.setSid(_nextWorkOrderSequence);
            }
          };
        EngineerWorkOrder _doubleArrow = ObjectExtensions.<EngineerWorkOrder>operator_doubleArrow(_createAndAddtoEngineerWorkOrders, _function_1);
        wo = _doubleArrow;
      }
      _xblockexpression = (wo);
    }
    return _xblockexpression;
  }
  
  public boolean isAllTaskFinishedorCancelled() {
    final Function1<EngineerWorkOrder,Boolean> _function = new Function1<EngineerWorkOrder,Boolean>() {
        public Boolean apply(final EngineerWorkOrder it) {
          boolean _or = false;
          Boolean _isFinished = it.isFinished();
          if ((_isFinished).booleanValue()) {
            _or = true;
          } else {
            Boolean _isPending = it.isPending();
            _or = ((_isFinished).booleanValue() || (_isPending).booleanValue());
          }
          return Boolean.valueOf(_or);
        }
      };
    boolean _forall = IterableExtensions.<EngineerWorkOrder>forall(this.engineerWorkOrders, _function);
    return _forall;
  }
  
  public String getRCProjectName() {
    String _rCProjectName = this.engineerProject.getRCProjectName();
    return _rCProjectName;
  }
  
  public String getRCProjectCode() {
    String _rCProjectCode = this.engineerProject.getRCProjectCode();
    return _rCProjectCode;
  }
  
  public static EngineerProjectJob create(final EngineerProject engineerProject, final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerProjectJob engineerProjectJob = new com.shrcl.engineerprocess.domain.impl.EngineerProjectJobImpl(
    	engineerProject
    );
    objectFactory.create(engineerProjectJob);
    engineerProjectJob.start();
    return engineerProjectJob;			
    
  }
  
  public static EngineerProjectJob createEngineerProjectJobImpl(final EngineerProject engineerProject, final IObjectFactory objectFactory, final Procedure1<EngineerProjectJob> init) {
    com.shrcl.engineerprocess.domain.EngineerProjectJob engineerProjectJob = new com.shrcl.engineerprocess.domain.impl.EngineerProjectJobImpl(
    	engineerProject
    );
    objectFactory.create(engineerProjectJob);
    init.apply(engineerProjectJob);
    engineerProjectJob.start();
    
    return engineerProjectJob;			
    
  }
  
  public EngineerProjectJobProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerProjectJobProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerProjectJobProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
